﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.Net;
using System.Net.Sockets;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
using IPC.Communication.Framework.Core.IMessage;

namespace IPC.Communication.Framework.Core.Net
{
    public class NetworkServerBase : NetworkXBase
    {
        public bool IsStarted
        {
            get;
            protected set;
        }

        public int Port
        {
            get;
            set;
        }

        public NetworkServerBase()
        {
            IsStarted = false;
            Port = 0;
        }

        protected void AsyncAcceptCallback(IAsyncResult iar)
        {
            Socket socket = iar.AsyncState as Socket;
            if (socket != null)
            {
                Socket socket2 = null;
                try
                {
                    socket2 = socket.EndAccept(iar);
                    ThreadPool.QueueUserWorkItem(ThreadPoolLogin, socket2);
                }
                catch (ObjectDisposedException)
                {
                    return;
                }
                catch (Exception ex2)
                {
                    if (socket2 != null)
                    {
                        socket2.Close();
                    }
                    if (base.LogNet != null)
                    {
                        base.LogNet.WriteException(ToString(), StringResources.Language.SocketAcceptCallbackException, ex2);
                    }
                }
                int num = 0;
                while (num < 3)
                {
                    try
                    {
                        socket.BeginAccept(AsyncAcceptCallback, socket);
                    }
                    catch (Exception ex3)
                    {
                        Thread.Sleep(1000);
                        if (base.LogNet != null)
                        {
                            base.LogNet.WriteException(ToString(), StringResources.Language.SocketReAcceptCallbackException, ex3);
                        }
                        num++;
                        continue;
                    }
                    break;
                }
                if (num >= 3)
                {
                    if (base.LogNet != null)
                    {
                        base.LogNet.WriteError(ToString(), StringResources.Language.SocketReAcceptCallbackException);
                    }
                    throw new Exception(StringResources.Language.SocketReAcceptCallbackException);
                }
            }
        }

        private void ThreadPoolLogin(object obj)
        {
            Socket socket = obj as Socket;
            if (socket != null)
            {
                IPEndPoint iPEndPoint = (IPEndPoint)socket.RemoteEndPoint;
                OperateResult operateResult = SocketAcceptExtraCheck(socket, iPEndPoint);
                if (!operateResult.IsSuccess)
                {
                    if (base.LogNet != null)
                    {
                        base.LogNet.WriteDebug(ToString(), String.Format("[{0}] Socket Accept Extra Check Failed : {1}", iPEndPoint, operateResult.Message));
                    }
                    if (socket != null)
                    {
                        socket.Close();
                    }
                }
                else
                {
                    ThreadPoolLogin(socket, iPEndPoint);
                }
            }
        }

        protected virtual void ThreadPoolLogin(Socket socket, IPEndPoint endPoint)
        {
            if (socket != null)
            {
                socket.Close();
            }
        }

        protected virtual OperateResult SocketAcceptExtraCheck(Socket socket, IPEndPoint endPoint)
        {
            return OperateResult.CreateSuccessResult();
        }

        protected virtual void StartInitialization()
        {
        }

        public virtual void ServerStart(int port)
        {
            if (!IsStarted)
            {
                StartInitialization();
                CoreSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                CoreSocket.Bind(new IPEndPoint(IPAddress.Any, port));
                CoreSocket.Listen(500);
                CoreSocket.BeginAccept(AsyncAcceptCallback, CoreSocket);
                IsStarted = true;
                Port = port;
                if (base.LogNet != null)
                {
                    base.LogNet.WriteInfo(ToString(), StringResources.Language.NetEngineStart);
                }
            }
        }

        public void ServerStart()
        {
            ServerStart(Port);
        }

        protected virtual void CloseAction()
        {
        }

        public virtual void ServerClose()
        {
            if (IsStarted)
            {
                IsStarted = false;
                CloseAction();
                if (CoreSocket != null)
                {
                    CoreSocket.Close();
                }
                if (base.LogNet != null)
                {
                    base.LogNet.WriteInfo(ToString(), StringResources.Language.NetEngineClose);
                }
            }
        }

        private byte[] CreateHslAlienMessage(string dtuId, string password)
        {
            if (dtuId.Length > 11)
            {
                dtuId = dtuId.Substring(11);
            }
            byte[] array = new byte[28]
		{
			72,
			115,
			110,
			0,
			23,
			0,
			0,
			0,
			0,
			0,
			0,
			0,
			0,
			0,
			0,
			0,
			0,
			0,
			0,
			0,
			0,
			0,
			0,
			0,
			0,
			0,
			0,
			0
		};
            if (dtuId.Length > 11)
            {
                dtuId = dtuId.Substring(0, 11);
            }
            Encoding.ASCII.GetBytes(dtuId).CopyTo(array, 5);
            if (!string.IsNullOrEmpty(password))
            {
                if (password.Length > 6)
                {
                    password = password.Substring(6);
                }
                Encoding.ASCII.GetBytes(password).CopyTo(array, 16);
            }
            return array;
        }

        public OperateResult ConnectHslAlientClient(string ipAddress, int port, string dtuId, string password = "")
        {
            byte[] data = CreateHslAlienMessage(dtuId, password);
            OperateResult<Socket> operateResult = CreateSocketAndConnect(ipAddress, port, 10000);
            if (!operateResult.IsSuccess)
            {
                return operateResult;
            }
            OperateResult operateResult2 = Send(operateResult.Content, data);
            if (!operateResult2.IsSuccess)
            {
                return operateResult2;
            }
            OperateResult<byte[]> operateResult3 = ReceiveByMessage(operateResult.Content, 10000, new AlienMessage());
            if (!operateResult3.IsSuccess)
            {
                return operateResult3;
            }
            switch (operateResult3.Content[5])
            {
                case 1:
                    if (operateResult.Content != null)
                    {
                        operateResult.Content.Close();
                    }
                    return new OperateResult(StringResources.Language.DeviceCurrentIsLoginRepeat);
                case 2:
                    if (operateResult.Content != null)
                    {
                        operateResult.Content.Close();
                    }
                    return new OperateResult(StringResources.Language.DeviceCurrentIsLoginForbidden);
                case 3:
                    if (operateResult.Content != null)
                    {
                        operateResult.Content.Close();
                    }
                    return new OperateResult(StringResources.Language.PasswordCheckFailed);
                default:
                    ThreadPoolLogin(operateResult.Content);
                    return OperateResult.CreateSuccessResult();
            }
        }

        //[AsyncStateMachine(typeof(<ConnectHslAlientClientAsync>d__20))]
        //[DebuggerStepThrough]
        //public Task<OperateResult> ConnectHslAlientClientAsync(string ipAddress, int port, string dtuId, string password = "")
        //{
        //    <ConnectHslAlientClientAsync>d__20 stateMachine = new <ConnectHslAlientClientAsync>d__20();
        //    stateMachine.<>t__builder = AsyncTaskMethodBuilder<OperateResult>.Create();
        //    stateMachine.<>4__this = this;
        //    stateMachine.ipAddress = ipAddress;
        //    stateMachine.port = port;
        //    stateMachine.dtuId = dtuId;
        //    stateMachine.password = password;
        //    stateMachine.<>1__state = -1;
        //    stateMachine.<>t__builder.Start(ref stateMachine);
        //    return stateMachine.<>t__builder.Task;
        //}

        public override string ToString()
        {
            return String.Format("NetworkServerBase[{0}]", Port);
        }
    }
}
